<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
  /***
   * 等待者模式：通过对多个异步进程监听，来触发未来发生的动作
   *
   * 下面手写一个简单的promise
   ***/
//  等待者对象
  let Waiter = function () {
    //注册了的等待对象容器
    let dfd = [],
      //成果回调方法容器
      doneArr = [],
      //失败回调方法容器
      failArr =[],
      //缓存Array方法
      slice = Array.prototype.slice,
      //缓存this
      that = this;
    //监控对象类
    let Primise = function (){
      this.resolved = false;
      this.rejected = false;
    }
    //监控对象类原型
    Primise.prototype = {
      resolve : function (){
      //  设置当前监控对象成功
        this.resolved = true;
      //如果没有监控对象则取消执行
        if(dfd.length){
          return;
        }
        for(let i = dfd.length - 1 ; i >= 0;i--){
        //  如果在任意一个监控对象没有被解决或者解决失败时返回
          if(dfd[i] && !dfd[i].resolve || dfd[i].reject){
            return;
          }
        //  清除监控对象
          dfd.splice(i,1);
        }
      //  执行解决成功回调方法
        _exec(doneArr);
      },
      reject: function (){
      //  设置当前监控对象解决失败
        this.rejectd = true;
      //  如果没有监控对象则取消执行
        if(!dfd.length){
          return;
        //  清除所有监控对象
          dfd.splice(0);
        //  执行解决成功回调方法
          _exec(failArr);
        }
      }
    }
    //创建监控对象
    that.Deferred = function () {
      return new Primise();
    }
    //回调执行方法
    function _exec(arr){
      for(let i = 0;i<arr.length;i++){
        try{
          arr[i] && arr[i]();
        }catch (e){}
      }
    }
    //监控异步方法 参数，监控对象
    that.when = function (){
    //  设置监控对象
      dfd = slice.call(arguments);
    //  获取监控对象数组长度
      let i = dfd.length;
    //  向前遍历对象，最后一个对象的索引值是length - 1
      for(--i;i >= 0 ;i--){
      //  如果不存在监控对象，或者监控对象已经解决或者不是监控对象
        if(!dfd[i] || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof Primise){
        //  清理内存，清除当前监控对象
          dfd.splice(i,1)
        }
      }
      //返回等待者对象
      return that;
    };
    //解决成果回调函数添加方法
    that.done = function (){};
    //解决失败回调函数添加方法
    that.fail = function (){};
  }
</script>
</body>
</html>
